#include "o_o.h"


oBall::oBall(ofxVec2f pos, ofxVec2f dir, float radius)
{
	this->pos = pos;
	this->dir = dir;
	this->radius = radius;
}


o_o::o_o(osCamerahandler *camera,colorHandler *colors)
{
	this->camera = camera;
	this->colors = colors;
	field  = *(new ofRectangle(1, 0, 796, 599));
	lastHitTime = time(NULL)-1;
		
	resetGame();
	
}

o_o::~o_o(void)
{
}



void o_o::draw(int screenoffset)
{

	
	
	for(int b=0;b<Balls.size();b++)
	{
		ofNoFill();
		ofSetColor(colors->foregroundcolor);
		for(int i=0;i<10;i++)
			ofCircle(screenoffset+Balls[b].pos.x, Balls[b].pos.y, Balls[b].radius*(1-i*0.02f));
		
		ofFill();
		ofSetColor(colors->fillcolor);
		ofCircle(screenoffset+Balls[b].pos.x, Balls[b].pos.y, Balls[b].radius*(1-10*0.02f));

	}


	ofSetColor(colors->fillcolor);
	ofFill();
	for(int i = 0;i < players.size();i++) 
	{
		ofCircle(screenoffset+players[i].x, players[i].y, playersRadius);
		ofNoFill();
		ofSetColor(colors->foregroundcolor);
		for(int j=0;j<10;j++)
			ofCircle(screenoffset+players[i].x, players[i].y, playersRadius*(1-i*0.02f));
		
		ofFill();
		ofSetColor(colors->fillcolor);
		ofCircle(screenoffset+players[i].x, players[i].y, playersRadius*(1-10*0.02f));

		/*if(i+1 < players.size())
		{
			ofLine(screenoffset+players[i].x, players[i].y,screenoffset+players[i+1].x, players[i+1].y);
			ofLine(screenoffset+players[i].x, players[i].y,screenoffset+players[i+1].x, players[i+1].y);
			ofLine(screenoffset+players[i].x-2, players[i].y-2,screenoffset+players[i+1].x-2, players[i+1].y-2);
			ofLine(screenoffset+players[i].x-2, players[i].y-2,screenoffset+players[i+1].x-2, players[i+1].y-2);
		}*/
	}

	ofFill();
	//Draw score
	ostringstream scorestring;
	scorestring  << lifes << endl;
	
	ofDrawBitmapString( scorestring.str(), screenoffset+(field.width/2),field.y+40);  
	ofDrawBitmapString( scorestring.str(), screenoffset+(field.width/2),field.y+40);  
}
void o_o::update()
{

	players.clear();
	//TODO: Sort blobs by id
	//std::sort(camera->trackedBlobs.begin(),camera->trackedBlobs.end(),SortById());
	for(int i = 0;i < camera->trackedBlobs.size();i++) 
	{
		players.push_back(*(new ofPoint(camera->trackedBlobs[i].center.x, camera->trackedBlobs[i].center.y)));
	}
	if(players.size()==1)
		players.push_back(*(new ofPoint(field.x+field.width/2,field.y+field.height/2)));


	//==Set ball size
	
	//Get total length of playerchain
	float length = 0;
	for(int i = 1;i < players.size();i++) 
	{
		ofxVec2f l = ofxVec2f(players[i].x-players[i-1].x,players[i].y-players[i-1].y);
		length += l.length();
	}
	float maxLength = sqrtf(pow(field.height,2.0f)+pow(field.width,2.0f))*players.size();

	//Move, resize and check for bounces for all balls
	for(int i=0;i<Balls.size();i++)
	{
		if(length>0 && false) //Fixed size :P
			Balls[i].radius = (maxLength/length)*4;
		else
			Balls[i].radius = 60;
		if(Balls[i].radius<12)
			Balls[i].radius = 12;
		if(Balls[i].radius>60)
			Balls[i].radius = 60;
		
		//Move ball
		
		//Only move if not hit pause
		if(lastHitTime<time(NULL))
			Balls[i].pos += Balls[i].dir.normalized()*3.5f;

		//top
		if(Balls[i].dir.y<0 &&  Balls[i].pos.y-Balls[i].radius < field.y) {
			Balls[i].dir.y *=-1;
			Balls[i].dir.x +=ofRandom(-0.5f,0.5f);
			//Move the ball twice to avoid it getting stuck
			
		}
		//bottom
		if(Balls[i].dir.y>0 && Balls[i].pos.y+Balls[i].radius > field.y+field.height ) {
			Balls[i].dir.y *=-1;
			Balls[i].dir.x +=ofRandom(-0.5f,0.5f);
			//Move the ball twice to avoid it getting stuck
			
		}
		//left
		if(Balls[i].dir.x<0 &&  Balls[i].pos.x-Balls[i].radius < field.x) {
			Balls[i].dir.x *=-1;
			Balls[i].dir.y +=ofRandom(-0.5f,0.5f);
			//Move the ball twice to avoid it getting stuck
			
		}
		//rigth
		if(Balls[i].dir.x>0 && Balls[i].pos.x+Balls[i].radius > field.x+field.width ) {
			Balls[i].dir.x *=-1;
			Balls[i].dir.y +=ofRandom(-0.5f,0.5f);
			//Move the ball twice to avoid it getting stuck
			
		}
	}
	//Player collisions and lifes
	bool isHit = collisionWithPlayer(); //|| collisionWithPlayerChain();
	if(!lifeLostInLastFrame && isHit)
	{
		//TODO:Give feedback
		lastHitTime = time(NULL)+3;
	}
	lifeLostInLastFrame = isHit;
}

bool o_o::collisionWithPlayer()
{
	for(int i = 0;i < players.size();i++) 
	{
		for(int j = 0;j<Balls.size();j++)
		{
			ofxVec2f l = ofxVec2f(players[i].x-Balls[j].pos.x,players[i].y-Balls[j].pos.y);
		if(Balls[j].radius+playersRadius>l.length())
			return true;
		}
	}
	
	return false;
}
bool o_o::collisionWithPlayerChain()
{
	for(int i = 1;i < players.size(); i++) 
	{
		for(int j = 0;j<Balls.size();j++)
		{
	
		
		ofxVec2f c = ClosestPointOnSegment(Balls[j].pos,ofxVec2f(players[i].x,players[i].y),ofxVec2f(players[i-1].x,players[i-1].y));
		ofxVec2f l = ofxVec2f(Balls[j].pos.x-c.x,Balls[j].pos.y-c.y);
		float length = l.length();
		if(Balls[j].radius>length)
			return true;
		}
	}
	
	return false;
}


ofxVec2f o_o::ClosestPointOnSegment(ofxVec2f p, ofxVec2f p1, ofxVec2f p2)
{
	
    ofxVec2f diff = p-p1;
    ofxVec2f dir = p2-p1;
	float t = diff.dot(dir)/dir.dot(dir);
    if (t <= 0.0f) {
        return p1;
    } else if (t >= 1.0f) {
        return p2;
    } else {
        return p1 + t * dir;
    }
}

void o_o::resetGame()
{
	stopGame();
	startGame();
}
void o_o::stopGame()
{
}
void o_o::startGame()
{
	lifeLostInLastFrame = false;
	lifes = 10;
	Balls.clear();
	for(int i=0;i<2;i++)
	{
		ofxVec2f dir = ofxVec2f(ofRandom(-1.0f,1.0f),ofRandom(-1.0f,1.0f));
		dir.normalize();
		Balls.push_back(*(new oBall(ofxVec2f(field.x+field.width/2,field.y+field.height/2),dir,10)));
	}
}